package ai.people.platform.system.service.impl;

import ai.people.core.security.support.RequestHolderUtil;
import ai.people.netmon.framework.domain.system.entity.NmSystemMenu;
import ai.people.netmon.framework.domain.system.vo.NmSystemMenuVO;
import ai.people.netmon.framework.exception.enums.AccountExceptionEnum;
import ai.people.netmon.framework.exception.enums.CommonEnum;
import ai.people.netmon.framework.exception.enums.SystemExceptionEnum;
import ai.people.netmon.framework.utils.AssertUtils;
import ai.people.netmon.utils.NumeralPool;
import ai.people.platform.system.mapper.SystemMenuMapper;
import ai.people.platform.system.service.SysRoleMenuService;
import ai.people.platform.system.service.SystemMenuService;
import ai.people.platform.system.service.SystemUserService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 系统菜单服务impl
 *
 * @author yuanqinglong
 * @date 2022/3/4 15:53
 */
@Service
@RefreshScope
public class SystemMenuServiceImpl implements SystemMenuService {

    /**
     * 系统菜单映射器
     */
    @Autowired
    private SystemMenuMapper systemMenuMapper;

    /**
     * 系统角色菜单服务
     */
    @Autowired
    private SysRoleMenuService sysRoleMenuService;

    /**
     * 系统用户服务impl
     */
    @Autowired
    private SystemUserService systemUserServiceImpl;
    
    /**
     * 顶级父id
     */
    @Value("${menu.top.parentId}")
    private Long topParentId;


    /**
     * 查询用户菜单树
     *
     * @param userId 用户id
     * @return {@link List}<{@link NmSystemMenu}>
     */
    @Override
    public List<NmSystemMenuVO> listMenuTree(Long userId) {
        List<NmSystemMenu> menuList = this.listUserMenus(userId);
        List<NmSystemMenuVO> nmSystemMenuVOS = JSONArray.parseArray(JSON.toJSONString(menuList), NmSystemMenuVO.class);
        return this.generateMenuTree(nmSystemMenuVOS);
    }


    /**
     * 用户菜单列表
     *
     * @param userId 用户id
     * @return {@link List}<{@link NmSystemMenu}>
     */
    @Override
    public List<NmSystemMenu> listUserMenus(Long userId) {
        systemUserServiceImpl.checkUserExists(userId);
        List<NmSystemMenu> systemMenuList = systemMenuMapper.getMenuByUserId(userId);
        AssertUtils.isFalse(systemMenuList.isEmpty(), AccountExceptionEnum.ACCOUNT_IS_NOT_ASSIGNED_A_MENU);
        return systemMenuList;
    }

    /**
     * 添加菜单
     *
     * @param nmSystemMenu 纳米系统菜单
     */
    @Override
    public void addMenu(NmSystemMenu nmSystemMenu) {
        this.checkMenuInfo(nmSystemMenu);
        LambdaQueryWrapper<NmSystemMenu> lambdaQuery = Wrappers.lambdaQuery();
        lambdaQuery.select(NmSystemMenu::getId).eq(NmSystemMenu::getMenuName, nmSystemMenu.getMenuName());
        List<NmSystemMenu> menuList = systemMenuMapper.selectList(lambdaQuery);
        AssertUtils.isTrue(menuList.isEmpty(), SystemExceptionEnum.DUPLICATE_MENU_NAME);

        nmSystemMenu.setCreateUserId(RequestHolderUtil.getUserId());
        int insertResult = systemMenuMapper.insert(nmSystemMenu);
        AssertUtils.isTrue(insertResult > NumeralPool.ZERO, CommonEnum.FAIL);
    }


    /**
     * 删除菜单
     *
     * @param menuId 菜单id
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteMenu(Long menuId) {
        NmSystemMenu nmSystemMenu = systemMenuMapper.selectById(menuId);
        AssertUtils.isNotNull(nmSystemMenu, SystemExceptionEnum.MENU_DOES_NOT_EXIST);
        systemMenuMapper.deleteById(menuId);
        sysRoleMenuService.deleteRoleMenuByMenuId(menuId);
    }

    /**
     * 更新菜单
     *
     * @param nmSystemMenu 纳米系统菜单
     */
    @Override
    public void updateMenu(NmSystemMenu nmSystemMenu) {
        this.getMenuById(nmSystemMenu.getId());
        this.checkMenuInfo(nmSystemMenu);

        LambdaQueryWrapper<NmSystemMenu> lambdaQuery = Wrappers.lambdaQuery(NmSystemMenu.class);
        lambdaQuery.select(NmSystemMenu::getId).eq(NmSystemMenu::getMenuName, nmSystemMenu.getMenuName()).ne(NmSystemMenu::getId, nmSystemMenu.getId());
        List<NmSystemMenu> menuList = systemMenuMapper.selectList(lambdaQuery);
        AssertUtils.isTrue(menuList.isEmpty(), SystemExceptionEnum.DUPLICATE_MENU_NAME);

        nmSystemMenu.setUpdateTime(LocalDateTime.now());
        int updateResult = systemMenuMapper.updateById(nmSystemMenu);
        AssertUtils.isTrue(updateResult > NumeralPool.ZERO, CommonEnum.FAIL);
    }


    /**
     * 通过id获取菜单
     *
     * @param menuId 菜单id
     * @return {@link NmSystemMenu}
     */
    @Override
    public NmSystemMenu getMenuById(Long menuId) {
        NmSystemMenu nmSystemMenu = systemMenuMapper.selectById(menuId);
        AssertUtils.isNotNull(nmSystemMenu, SystemExceptionEnum.MENU_DOES_NOT_EXIST);
        return nmSystemMenu;
    }

    /**
     * 通过id批量查询菜单
     *
     * @param menuIds 菜单id
     * @return {@link List}<{@link Long}>
     */
    @Override
    public List<NmSystemMenu> listMenuInIds(List<Long> menuIds) {
        LambdaQueryWrapper<NmSystemMenu> lambdaQuery = Wrappers.lambdaQuery(NmSystemMenu.class);
        lambdaQuery.in(NmSystemMenu::getId, menuIds);
        return systemMenuMapper.selectList(lambdaQuery);
    }

    /**
     * 所有树
     *
     * @return {@link List}<{@link NmSystemMenuVO}>
     */
    @Override
    public List<NmSystemMenuVO> treeAll() {
        List<NmSystemMenu> nmSystemMenus = systemMenuMapper.selectList(Wrappers.lambdaQuery());
        List<NmSystemMenuVO> nmSystemMenuVOS = JSONArray.parseArray(JSON.toJSONString(nmSystemMenus), NmSystemMenuVO.class);
        return this.generateMenuTree(nmSystemMenuVOS);
    }


    /**
     * 检查菜单信息
     *
     * @param nmSystemMenu 纳米系统菜单
     */
    private void checkMenuInfo(NmSystemMenu nmSystemMenu) {
        if (!Objects.equals(topParentId, nmSystemMenu.getParentId())) {
            NmSystemMenu systemMenu = systemMenuMapper.selectById(nmSystemMenu.getParentId());
            AssertUtils.isNotNull(systemMenu, SystemExceptionEnum.PARENT_MENU_DOES_NOT_EXIST);
        }
    }


    /**
     * 生成菜单树
     *
     * @param nmSystemMenuVOS 纳米系统菜单vos
     * @return {@link List}<{@link NmSystemMenuVO}>
     */
    private List<NmSystemMenuVO> generateMenuTree(List<NmSystemMenuVO> nmSystemMenuVOS) {
        // 按parentId分组
        Map<Long, List<NmSystemMenuVO>> groupByParent = nmSystemMenuVOS.stream().collect(Collectors.groupingBy(NmSystemMenuVO::getParentId));
        // 子菜单
        List<NmSystemMenuVO> subsetMenus = nmSystemMenuVOS.stream().filter(menu -> !Objects.equals(menu.getParentId(), topParentId)).collect(Collectors.toList());
        // 封装菜单子集
        subsetMenus.forEach(nmSystemMenu -> nmSystemMenu.setChildren(groupByParent.getOrDefault(nmSystemMenu.getId(), Collections.emptyList())));
        return nmSystemMenuVOS.stream().filter(menu -> Objects.equals(menu.getParentId(), topParentId))
                .peek(menu -> menu.setChildren(groupByParent.getOrDefault(menu.getId(), Collections.emptyList()))).collect(Collectors.toList());
    }
}
